//package com.tushen.labor.util;
//
//
//import android.os.Handler;
//
//import android.os.Looper;
//
//import android.os.Message;
//
//import java.lang.ref.WeakReference;
//
//import java.util.concurrent.locks.Lock;
//
//import java.util.concurrent.locks.ReentrantLock;
//
//
//
///**
//
// * Memory safer implementation of android.os.Handler
//
// * <p/>
//
// * Original implementation of Handlers always keeps hard reference to handler in queue of execution.
//
// * If you create anonymous handler and post delayed message into it, it will keep all parent class
//
// * for that time in memory even if it could be cleaned.
//
// * <p/>
//
// * This implementation is trickier, it will keep WeakReferences to runnables and messages,
//
// * and GC could collect them once WeakHandler instance is not referenced any more
//
// * <p/>
//
// *
//
// * @see Handler
//
// *
//
// * Created by Dmytro Voronkevych on 17/06/2014.
//
// */
//
//@SuppressWarnings("unused")
//
//public class WeakHandler {
//
//    private final Handler.Callback mCallback; // hard reference to Callback. We need to keep callback in memory
//
//    private final ExecHandler mExec;
//
//    private Lock mLock = new ReentrantLock();
//
//    @SuppressWarnings("ConstantConditions")
//
//    @VisibleForTesting
//
//    final ChainedRef mRunnables = new ChainedRef(mLock, null);
//
//
//
//    /**
//
//     * Default constructor associates this handler with the {@link Looper} for the
//
//     * current thread.
//
//     *
//
//     * If this thread does not have a looper, this handler won't be able to receive messages
//
//     * so an exception is thrown.
//
//     */
//
//    public WeakHandler() {
//
//        mCallback = null;
//
//        mExec = new ExecHandler();
//
//    }
//
//
//
//    /**
//
//     * Constructor associates this handler with the {@link Looper} for the
//
//     * current thread and takes a callback interface in which you can handle
//
//     * messages.
//
//     *
//
//     * If this thread does not have a looper, this handler won't be able to receive messages
//
//     * so an exception is thrown.
//
//     *
//
//     * @param callback The callback interface in which to handle messages, or null.
//
//     */
//
//    public WeakHandler(@Nullable Handler.Callback callback) {
//
//        mCallback = callback; // Hard referencing body
//
//        mExec = new ExecHandler(new WeakReference<>(callback)); // Weak referencing inside ExecHandler
//
//    }
//
//
//
//    /**
//
//     * Use the provided {@link Looper} instead of the default one.
//
//     *
//
//     * @param looper The looper, must not be null.
//
//     */
//
//    public WeakHandler(@NonNull Looper looper) {
//
//        mCallback = null;
//
//        mExec = new ExecHandler(looper);
//
//    }
//
//
//
//    /**
//
//     * Use the provided {@link Looper} instead of the default one and take a callback
//
//     * interface in which to handle messages.
//
//     *
//
//     * @param looper The looper, must not be null.
//
//     * @param callback The callback interface in which to handle messages, or null.
//
//     */
//
//    public WeakHandler(@NonNull Looper looper, @NonNull Handler.Callback callback) {
//
//        mCallback = callback;
//
//        mExec = new ExecHandler(looper, new WeakReference<>(callback));
//
//    }
//
//
//
//    /**
//
//     * Causes the Runnable r to be added to the message queue.
//
//     * The runnable will be run on the thread to which this handler is
//
//     * attached.
//
//     *
//
//     * @param r The Runnable that will be executed.
//
//     *
//
//     * @return Returns true if the Runnable was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.
//
//     */
//
//    public final boolean post(@NonNull Runnable r) {
//
//        return mExec.post(wrapRunnable(r));
//
//    }
//
//
//
//    /**
//
//     * Causes the Runnable r to be added to the message queue, to be run
//
//     * at a specific time given by <var>uptimeMillis</var>.
//
//     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
//
//     * The runnable will be run on the thread to which this handler is attached.
//
//     *
//
//     * @param r The Runnable that will be executed.
//
//     * @param uptimeMillis The absolute time at which the callback should run,
//
//     *         using the {@link android.os.SystemClock#uptimeMillis} time-base.
//
//     *
//
//     * @return Returns true if the Runnable was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.  Note that a
//
//     *         result of true does not mean the Runnable will be processed -- if
//
//     *         the looper is quit before the delivery time of the message
//
//     *         occurs then the message will be dropped.
//
//     */
//
//    public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
//
//        return mExec.postAtTime(wrapRunnable(r), uptimeMillis);
//
//    }
//
//
//
//    /**
//
//     * Causes the Runnable r to be added to the message queue, to be run
//
//     * at a specific time given by <var>uptimeMillis</var>.
//
//     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
//
//     * The runnable will be run on the thread to which this handler is attached.
//
//     *
//
//     * @param r The Runnable that will be executed.
//
//     * @param uptimeMillis The absolute time at which the callback should run,
//
//     *         using the {@link android.os.SystemClock#uptimeMillis} time-base.
//
//     *
//
//     * @return Returns true if the Runnable was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.  Note that a
//
//     *         result of true does not mean the Runnable will be processed -- if
//
//     *         the looper is quit before the delivery time of the message
//
//     *         occurs then the message will be dropped.
//
//     *
//
//     * @see android.os.SystemClock#uptimeMillis
//
//     */
//
//    public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) {
//
//        return mExec.postAtTime(wrapRunnable(r), token, uptimeMillis);
//
//    }
//
//
//
//    /**
//
//     * Causes the Runnable r to be added to the message queue, to be run
//
//     * after the specified amount of time elapses.
//
//     * The runnable will be run on the thread to which this handler
//
//     * is attached.
//
//     *
//
//     * @param r The Runnable that will be executed.
//
//     * @param delayMillis The delay (in milliseconds) until the Runnable
//
//     *        will be executed.
//
//     *
//
//     * @return Returns true if the Runnable was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.  Note that a
//
//     *         result of true does not mean the Runnable will be processed --
//
//     *         if the looper is quit before the delivery time of the message
//
//     *         occurs then the message will be dropped.
//
//     */
//
//    public final boolean postDelayed(Runnable r, long delayMillis) {
//
//        return mExec.postDelayed(wrapRunnable(r), delayMillis);
//
//    }
//
//
//
//    /**
//
//     * Posts a message to an object that implements Runnable.
//
//     * Causes the Runnable r to executed on the next iteration through the
//
//     * message queue. The runnable will be run on the thread to which this
//
//     * handler is attached.
//
//     * <b>This method is only for use in very special circumstances -- it
//
//     * can easily starve the message queue, cause ordering problems, or have
//
//     * other unexpected side-effects.</b>
//
//     *
//
//     * @param r The Runnable that will be executed.
//
//     *
//
//     * @return Returns true if the message was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.
//
//     */
//
//    public final boolean postAtFrontOfQueue(Runnable r) {
//
//        return mExec.postAtFrontOfQueue(wrapRunnable(r));
//
//    }
//
//
//
//    /**
//
//     * Remove any pending posts of Runnable r that are in the message queue.
//
//     */
//
//    public final void removeCallbacks(Runnable r) {
//
//        final WeakRunnable runnable = mRunnables.remove(r);
//
//        if (runnable != null) {
//
//            mExec.removeCallbacks(runnable);
//
//        }
//
//    }
//
//
//
//    /**
//
//     * Remove any pending posts of Runnable <var>r</var> with Object
//
//     * <var>token</var> that are in the message queue.  If <var>token</var> is null,
//
//     * all callbacks will be removed.
//
//     */
//
//    public final void removeCallbacks(Runnable r, Object token) {
//
//        final WeakRunnable runnable = mRunnables.remove(r);
//
//        if (runnable != null) {
//
//            mExec.removeCallbacks(runnable, token);
//
//        }
//
//    }
//
//
//
//    /**
//
//     * Pushes a message onto the end of the message queue after all pending messages
//
//     * before the current time. It will be received in callback,
//
//     * in the thread attached to this handler.
//
//     *
//
//     * @return Returns true if the message was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.
//
//     */
//
//    public final boolean sendMessage(Message msg) {
//
//        return mExec.sendMessage(msg);
//
//    }
//
//
//
//    /**
//
//     * Sends a Message containing only the what value.
//
//     *
//
//     * @return Returns true if the message was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.
//
//     */
//
//    public final boolean sendEmptyMessage(int what) {
//
//        return mExec.sendEmptyMessage(what);
//
//    }
//
//
//
//    /**
//
//     * Sends a Message containing only the what value, to be delivered
//
//     * after the specified amount of time elapses.
//
//     * @see #sendMessageDelayed(Message, long)
//
//     *
//
//     * @return Returns true if the message was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.
//
//     */
//
//    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
//
//        return mExec.sendEmptyMessageDelayed(what, delayMillis);
//
//    }
//
//
//
//    /**
//
//     * Sends a Message containing only the what value, to be delivered
//
//     * at a specific time.
//
//     * @see #sendMessageAtTime(Message, long)
//
//     *
//
//     * @return Returns true if the message was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.
//
//     */
//
//    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
//
//        return mExec.sendEmptyMessageAtTime(what, uptimeMillis);
//
//    }
//
//
//
//    /**
//
//     * Enqueue a message into the message queue after all pending messages
//
//     * before (current time + delayMillis). You will receive it in
//
//     * callback, in the thread attached to this handler.
//
//     *
//
//     * @return Returns true if the message was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.  Note that a
//
//     *         result of true does not mean the message will be processed -- if
//
//     *         the looper is quit before the delivery time of the message
//
//     *         occurs then the message will be dropped.
//
//     */
//
//    public final boolean sendMessageDelayed(Message msg, long delayMillis) {
//
//        return mExec.sendMessageDelayed(msg, delayMillis);
//
//    }
//
//
//
//    /**
//
//     * Enqueue a message into the message queue after all pending messages
//
//     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
//
//     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
//
//     * You will receive it in callback, in the thread attached
//
//     * to this handler.
//
//     *
//
//     * @param uptimeMillis The absolute time at which the message should be
//
//     *         delivered, using the
//
//     *         {@link android.os.SystemClock#uptimeMillis} time-base.
//
//     *
//
//     * @return Returns true if the message was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.  Note that a
//
//     *         result of true does not mean the message will be processed -- if
//
//     *         the looper is quit before the delivery time of the message
//
//     *         occurs then the message will be dropped.
//
//     */
//
//    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//
//        return mExec.sendMessageAtTime(msg, uptimeMillis);
//
//    }
//
//
//
//    /**
//
//     * Enqueue a message at the front of the message queue, to be processed on
//
//     * the next iteration of the message loop.  You will receive it in
//
//     * callback, in the thread attached to this handler.
//
//     * <b>This method is only for use in very special circumstances -- it
//
//     * can easily starve the message queue, cause ordering problems, or have
//
//     * other unexpected side-effects.</b>
//
//     *
//
//     * @return Returns true if the message was successfully placed in to the
//
//     *         message queue.  Returns false on failure, usually because the
//
//     *         looper processing the message queue is exiting.
//
//     */
//
//    public final boolean sendMessageAtFrontOfQueue(Message msg) {
//
//        return mExec.sendMessageAtFrontOfQueue(msg);
//
//    }
//
//
//
//    /**
//
//     * Remove any pending posts of messages with code 'what' that are in the
//
//     * message queue.
//
//     */
//
//    public final void removeMessages(int what) {
//
//        mExec.removeMessages(what);
//
//    }
//
//
//
//    /**
//
//     * Remove any pending posts of messages with code 'what' and whose obj is
//
//     * 'object' that are in the message queue.  If <var>object</var> is null,
//
//     * all messages will be removed.
//
//     */
//
//    public final void removeMessages(int what, Object object) {
//
//        mExec.removeMessages(what, object);
//
//    }
//
//
//
//    /**
//
//     * Remove any pending posts of callbacks and sent messages whose
//
//     * <var>obj</var> is <var>token</var>.  If <var>token</var> is null,
//
//     * all callbacks and messages will be removed.
//
//     */
//
//    public final void removeCallbacksAndMessages(Object token) {
//
//        mExec.removeCallbacksAndMessages(token);
//
//    }
//
//
//
//    /**
//
//     * Check if there are any pending posts of messages with code 'what' in
//
//     * the message queue.
//
//     */
//
//    public final boolean hasMessages(int what) {
//
//        return mExec.hasMessages(what);
//
//    }
//
//
//
//    /**
//
//     * Check if there are any pending posts of messages with code 'what' and
//
//     * whose obj is 'object' in the message queue.
//
//     */
//
//    public final boolean hasMessages(int what, Object object) {
//
//        return mExec.hasMessages(what, object);
//
//    }
//
//
//
//    public final Looper getLooper() {
//
//        return mExec.getLooper();
//
//    }
//
//
//
//    private WeakRunnable wrapRunnable(@NonNull Runnable r) {
//
//        //noinspection ConstantConditions
//
//        if (r == null) {
//
//            throw new NullPointerException("Runnable can't be null");
//
//        }
//
//        final ChainedRef hardRef = new ChainedRef(mLock, r);
//
//        mRunnables.insertAfter(hardRef);
//
//        return hardRef.wrapper;
//
//    }
//
//
//
//    private static class ExecHandler extends Handler {
//
//        private final WeakReference<Callback> mCallback;
//
//
//
//        ExecHandler() {
//
//            mCallback = null;
//
//        }
//
//
//
//        ExecHandler(WeakReference<Callback> callback) {
//
//            mCallback = callback;
//
//        }
//
//
//
//        ExecHandler(Looper looper) {
//
//            super(looper);
//
//            mCallback = null;
//
//        }
//
//
//
//        ExecHandler(Looper looper, WeakReference<Callback> callback) {
//
//            super(looper);
//
//            mCallback = callback;
//
//        }
//
//
//
//        @Override
//
//        public void handleMessage(@NonNull Message msg) {
//
//            if (mCallback == null) {
//
//                return;
//
//            }
//
//            final Callback callback = mCallback.get();
//
//            if (callback == null) { // Already disposed
//
//                return;
//
//            }
//
//            callback.handleMessage(msg);
//
//        }
//
//    }
//
//
//
//    static class WeakRunnable implements Runnable {
//
//        private final WeakReference<Runnable> mDelegate;
//
//        private final WeakReference<ChainedRef> mReference;
//
//
//
//        WeakRunnable(WeakReference<Runnable> delegate, WeakReference<ChainedRef> reference) {
//
//            mDelegate = delegate;
//
//            mReference = reference;
//
//        }
//
//
//
//        @Override
//
//        public void run() {
//
//            final Runnable delegate = mDelegate.get();
//
//            final ChainedRef reference = mReference.get();
//
//            if (reference != null) {
//
//                reference.remove();
//
//            }
//
//            if (delegate != null) {
//
//                delegate.run();
//
//            }
//
//        }
//
//    }
//
//
//
//    static class ChainedRef {
//
//        @Nullable
//
//        ChainedRef next;
//
//        @Nullable
//
//        ChainedRef prev;
//
//        @NonNull
//
//        final Runnable runnable;
//
//        @NonNull
//
//        final WeakRunnable wrapper;
//
//
//
//        @NonNull
//
//        Lock lock;
//
//
//
//        public ChainedRef(@NonNull Lock lock, @NonNull Runnable r) {
//
//            this.runnable = r;
//
//            this.lock = lock;
//
//            this.wrapper = new WeakRunnable(new WeakReference<>(r), new WeakReference<>(this));
//
//        }
//
//
//
//        public WeakRunnable remove() {
//
//            lock.lock();
//
//            try {
//
//                if (prev != null) {
//
//                    prev.next = next;
//
//                }
//
//                if (next != null) {
//
//                    next.prev = prev;
//
//                }
//
//                prev = null;
//
//                next = null;
//
//            } finally {
//
//                lock.unlock();
//
//            }
//
//            return wrapper;
//
//        }
//
//
//
//        public void insertAfter(@NonNull ChainedRef candidate) {
//
//            lock.lock();
//
//            try {
//
//                if (this.next != null) {
//
//                    this.next.prev = candidate;
//
//                }
//
//
//
//                candidate.next = this.next;
//
//                this.next = candidate;
//
//                candidate.prev = this;
//
//            } finally {
//
//                lock.unlock();
//
//            }
//
//        }
//
//
//
//        @Nullable
//
//        public WeakRunnable remove(Runnable obj) {
//
//            lock.lock();
//
//            try {
//
//                ChainedRef curr = this.next; // Skipping head
//
//                while (curr != null) {
//
//                    if (curr.runnable == obj) { // We do comparison exactly how Handler does inside
//
//                        return curr.remove();
//
//                    }
//
//                    curr = curr.next;
//
//                }
//
//            } finally {
//
//                lock.unlock();
//
//            }
//
//            return null;
//
//        }
//
//    }
//
//}